﻿//===============================================================================
// Microsoft Innovation Centre - Western Europe
// Copyright (c) 2008 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.WVB.Framework;
using Microsoft.WVB.Framework.DataServicesEntities;
using Microsoft.WVB.Silverlight.Infrastructure;
using Microsoft.Practices.Composite.Events;

namespace Microsoft.WVB.UI
{
    public class ExplorerModel : BaseController, IExplorerModel
    {
        protected Func<Program, DateTime> OrderByDate = delegate(Program p)
        {
            ProgramProperty pp = p.Properties.Where((prop) => prop.pvid == 5).FirstOrDefault();
            if (pp != null)
            {
                return DateTime.Parse(pp.Value, new CultureInfo("en-US"));
            }
            else
                return DateTime.MinValue;
        };

        protected Func<Program, Double> OrderByRank = delegate(Program p)
        {
            ProgramProperty pp = p.Properties.Where((prop) => prop.pvid == 2).FirstOrDefault();
            if (pp != null)
            {
                return Double.Parse(pp.Value, new CultureInfo("en-US"));
            }
            else
                return 0;
        };

        private int NumberOfItems = 9;
        private int _index = 0;
        private IEnumerable<IName> _OriginalList = null;

        public Boolean IsBuffering
        {
            get { return _IsBuffering; }
            set { _IsBuffering = value; OnPropertyChanged(this.GetPropertySymbol(o => o.IsBuffering)); }
        }
        private Boolean _IsBuffering;

        public IEnumerable RootCategories
        {
            get { return _RootCategories; }
            set { _RootCategories = value; OnPropertyChanged(this.GetPropertySymbol(o => o.RootCategories)); }
        }
        private IEnumerable _RootCategories;

        public IEnumerable SubCategories
        {
            get { return _SubCategories; }
            set { _SubCategories = value; OnPropertyChanged(this.GetPropertySymbol(o => o.SubCategories)); }
        }
        private IEnumerable _SubCategories;

        public IEnumerable DisplayItems
        {
            get { return _DisplayItems; }
            set { _DisplayItems = value; OnPropertyChanged(this.GetPropertySymbol(o => o.DisplayItems)); }
        }
        private IEnumerable _DisplayItems;

        internal IEnumerable Items
        {
            get { return _Items; }
            set 
            { 
                _Items = value; 
                OnPropertyChanged(this.GetPropertySymbol(o => o.Items));

                if (_Items != null)
                    this.DisplayItems = _Items.Cast<IName>().Take(NumberOfItems);
                else
                    this.DisplayItems = _Items;

                _index = 0;
            }
        }
        private IEnumerable _Items;

        public ExplorerModel()
        {
            LoadInitialData();
        }
 
        private void LoadInitialData()
        {
            IsBuffering = true;
            EventHandler<ExecuteQueryCompletedEventArgs> handler = null;
            DataFeedService feedSvc = IoC.Create<DataFeedService>();
            string uri = String.Format("{0}/Categories?$expand=ParentCategory,ChildCategories", feedSvc.RootService);

            if (handler == null)
            {
                handler = delegate(object sender, ExecuteQueryCompletedEventArgs e)
                {
                    IEnumerable<Category> ie = (IEnumerable<Category>)e.Result;
                    // TODO: When Astoria team will correct the Bug of expanding a Member and collections at the same time.
                    // Today, the condition is wrong because some subCategories can have other SubCategories and not being root categories !!!
                    List<Category> l = ie.Where(p => p.ChildCategories.Count != 0).ToList();
                    this.RootCategories = l;

                    IsBuffering = false;
                    feedSvc.ExecuteQueryCompleted -= handler;
                };
            }
            feedSvc.ExecuteQueryCompleted += handler;
            feedSvc.ExecuteQueryAsync<Category>(new Uri(uri, UriKind.Absolute), feedSvc);
        }

        public virtual void ResetData()
        {
            LoadInitialData();
            if (this.Items != null)
            {
                this.Items = null;
            }
        }

        public virtual void DrillDown(object selection)
        {
            IsBuffering = true;

            if (selection.GetType() == typeof(Category))
            {
                Category c = selection as Category;

                if (c != null)
                {
                    if (c.ChildCategories.Count > 0)
                    {
                        setItemsList<Category>("{0}/Categories({1})/ChildCategories?$expand=ChildCategories&$orderby=Name", c.pcid);
                    }
                    else
                    {
                        setItemsList<Program>("{0}/Categories({1})/Programs?$expand=Properties&$orderby=Name", c.pcid);
                    }
                }
            }
            else if (selection.GetType() == typeof(Program))
            {
                Program p = selection as Program;

                if (p != null)
                {
                    EventHandler<ExecuteQueryCompletedEventArgs> handler = null;
                    string uri = null;

                    DataFeedService feedSvc = IoC.Create<DataFeedService>();
                    uri = String.Format("{0}/Programs({1})?$expand=Properties,Categories,Schedules", feedSvc.RootService, p.programid);

                    if (handler == null)
                    {
                        handler = delegate(object sender, ExecuteQueryCompletedEventArgs e)
                        {
                            Program program = ((IEnumerable<Program>)e.Result).ToList().FirstOrDefault();

                            if (program != null)
                            {
                                IEventAggregator ag = IoC.GetCreate<IEventAggregator>();
                                ag.GetEvent<ProgramChangedEvent>().Publish(program);
                            }
                            IsBuffering = false;

                            feedSvc.ExecuteQueryCompleted -= handler;
                        };
                    }
                    feedSvc.ExecuteQueryCompleted += handler;
                    feedSvc.ExecuteQueryAsync<Program>(new Uri(uri, UriKind.Absolute), feedSvc);
                }
            }
        }

        public virtual void PageNext()
        {
            if (this.Items != null)
            {
                _index++;

                if (_index > 0)
                {
                    int skippedItems = _index * NumberOfItems;

                    if (skippedItems < Items.Cast<IName>().Count())
                        this.DisplayItems = Items.Cast<IName>().Skip((_index * NumberOfItems)).Take(NumberOfItems);
                    else
                    {
                        this.DisplayItems = Items.Cast<IName>().Take(NumberOfItems);
                        _index = 0;
                    }
                }
                else
                {
                    this.DisplayItems = Items.Cast<IName>().Take(NumberOfItems);
                }
            }
        }

        public virtual void PageBack()
        {
            if (this.Items != null)
            {
                _index--;

                if (_index > 0)
                {
                    this.DisplayItems = Items.Cast<IName>().Skip((_index * NumberOfItems)).Take(NumberOfItems);
                }
                else
                {
                    this.DisplayItems = Items.Cast<IName>().Take(NumberOfItems);
                }
            }
        }

        public virtual void Sort(ExplorerSorting sortCondition)
        {
            if (this.Items != null)
            {
                switch (sortCondition)
                {
                    case ExplorerSorting.Alphabetic:
                        {
                            this.Items = _Items.Cast<Program>().OrderBy((p) => p.Name);
                        }
                        break;

                    case ExplorerSorting.Date:
                        {
                            this.Items = _Items.Cast<Program>().OrderBy((p) => OrderByDate(p));
                        }
                        break;

                    case ExplorerSorting.Rank:
                        {
                            this.Items = _Items.Cast<Program>().OrderBy((p) => OrderByRank(p));
                        }
                        break;

                    default:
                        break;
                }
            }
        }

        private void setItemsList<T>(string query, Nullable<int> id)
        {
            EventHandler<ExecuteQueryCompletedEventArgs> handler = null;
            string uri = null;

            DataFeedService feedSvc = IoC.Create<DataFeedService>();
            
            if (id == null)
                uri = String.Format(query, feedSvc.RootService);
            else
                uri = String.Format(query, feedSvc.RootService, id);

            if (handler == null)
            {
                handler = delegate(object sender, ExecuteQueryCompletedEventArgs e)
                {
                    IEnumerable<T> ie = (IEnumerable<T>)e.Result;
                    List<T> l = ie.ToList();

                    if (typeof(T).Equals(typeof(Program)))
                    {
                        this.Items = l;
                        this._OriginalList = l.Cast<IName>();
                    }
                    else if (typeof(T).Equals(typeof(Category)))
                    {
                        this.SubCategories = l;
                    }
                    
                    IsBuffering = false;
                    feedSvc.ExecuteQueryCompleted -= handler;
                };
            }
            feedSvc.ExecuteQueryCompleted += handler;
            feedSvc.ExecuteQueryAsync<T>(new Uri(uri, UriKind.Absolute), feedSvc);   
        }

        private void filterDisplay(string query)
        {
            if ((_OriginalList != null) && (String.IsNullOrEmpty(query)))
            {
                this.Items = _OriginalList;
            }
            else if (!String.IsNullOrEmpty(query))
            {
               var newList = (from c in this.Items.Cast<IName>()
                              where c.Name.Contains(query)
                              select c).ToList();

               if (newList.Count > 0)
               {
                   this.Items = newList;
               }
               else
               {
                   this.Items = new List<IName>();
               }
            }
        }

        public void SetItemsNumberToDisplay(int number)
        {
            NumberOfItems = number;
        }

        #region IExplorerModel Members

        public void ApplyFilter(string filter)
        {
                filterDisplay(filter);
        }

        public void Search(string keyword)
        {
            this.IsBuffering = true;

            EventHandler<ExecuteQueryCompletedEventArgs> handler = null;
            DataFeedService feedSvc = IoC.Create<DataFeedService>();
            string uri = String.Format("{0}/Programs?$expand=Properties,Categories", feedSvc.RootService);

            if (handler == null)
            {
                handler = delegate(object sender, ExecuteQueryCompletedEventArgs e)
                {
                    IEnumerable<Program> ie = (IEnumerable<Program>)e.Result;
                    List<Program> l = (from p in ie
                                       where (p.Name.Contains(keyword) ||
                                       p.EpisodeTitle.Contains(keyword))
                                       select p).ToList();
                    if (l.Count > 0)
                        this.Items = l;

                    this.IsBuffering = false;
                    feedSvc.ExecuteQueryCompleted -= handler;
                };
            }
            feedSvc.ExecuteQueryCompleted += handler;
            feedSvc.ExecuteQueryAsync<Program>(new Uri(uri, UriKind.Absolute), feedSvc);
        }

        #endregion
    }
}
